package com.hspedu.spring.annotation;

import com.hspedu.spring.hspapplicationcontext.HspApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Charlie
 * @version 1.0
 * @date 5/11/2025 上午8:45
 * 类似于spring的ioc核心容器
 */
public class HspSpringApplicationContext {
    private Class configClass;
    //ioc是通过反射存放的对象
    private final ConcurrentHashMap<String, Object> ioc =
            new ConcurrentHashMap<>();

    public Object getBean(String name){
        return ioc.get(name);
    }


    public HspSpringApplicationContext(Class configClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        this.configClass = configClass;
        //System.out.println("this.configClass" + this.configClass);
        //先得到配置类HspSpringConfig value的那个值指定扫描包的路径
        ComponentScan componentScan =
                (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
        String path = componentScan.value();
        // System.out.println("path= " +  path);
        //得到包下面的所有资源(.class文件)
        //1 得到类的加载器，拿到out工作实际目录
        ClassLoader classLoader =
                HspApplicationContext.class.getClassLoader();
        //2 通过类的加载器获得要扫描包的资源,URL. 注意包的路径点表示，文件的路径用"/",这里需要替换掉

        path = path.replace(".", "/");

        System.out.println("替换以后得path是=" + path );
        URL resource =
                classLoader.getResource(path);
        System.out.println("resource =" + resource);
        //3. 将加载器的文件都进行遍历. 注意一个目录也可以当成一个文件

        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {

                //E:\springlearning28102025\springlearning\target\classes\com\hspedu\spring\component\UserService.class
                //反射需要 "."

                System.out.println("===============");
                // System.out.println(f.getAbsoluteFile());
                String fileAbsolutePath = f.getAbsolutePath();

                //这里需要再次过滤，只处理.class 文件
                if (fileAbsolutePath.endsWith(".class")) {


                    //1 获取到类名
                    String className =
                            fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                    //System.out.println("className = >" + className);

                    //2 获取类的全路径
                    String classFullName =
                            path.replace("/", ".") + "." + className;

                    System.out.println("classFullName =" + classFullName);

                    //3 判断类上的注解 @Component @Service
                    Class<?> aClass = classLoader.loadClass(classFullName);
                    //forName 反射加载可以得到对象     Class aclass = Class.forName(classFullName)
                    //会执行类的静态方法

                    // classloader.loadClass 不会调用静态方法
                    if (aClass.isAnnotationPresent(Component.class) ||
                            aClass.isAnnotationPresent(Controller.class) ||
                            aClass.isAnnotationPresent(Service.class) ||
                            aClass.isAnnotationPresent(Repository.class)) {
                        Class<?> clazz = Class.forName(classFullName);

                        Object instance = clazz.newInstance();
                        ioc.put(StringUtils.uncapitalize(className),instance);

                    }


                }

            }

        }


    }
}
